using Microsoft.EntityFrameworkCore;
using RAG.Domain.Services;
using RAG.Domain.Entities.App;
using RAG.Infrastructure.Data;
using Microsoft.Extensions.Logging;

namespace RAG.Application.Services;

public class DocumentApplicationService : IDocumentApplicationService
{
    private readonly RagAIDbContext _context;
    private readonly IFileStorage _fileStorage;
    private readonly ILogger<DocumentApplicationService> _logger;

    public DocumentApplicationService(RagAIDbContext context, IFileStorage fileStorage, ILogger<DocumentApplicationService> logger)
    {
        _context = context;
        _fileStorage = fileStorage;
        _logger = logger;
    }

    public async Task<UploadFilesResponse> UploadFilesAsync(UploadFilesRequest request, Guid userId)
    {
        var response = new UploadFilesResponse();
        var successDocuments = new List<DocumentInfo>();
        var failedDocuments = new List<UploadError>();

        foreach (var file in request.Files)
        {
            try
            {
                ValidateFile(file);
                var filePath = await _fileStorage.SaveAsync(file);

                var user = await _context.Users.FindAsync((object)userId);
                if (user == null)
                {
                    throw new InvalidOperationException($"用户不存在: {userId}");
                }

                var document = new Documents
                {
                    Title = Path.GetFileNameWithoutExtension(file.FileName),
                    FileName = file.FileName,
                    FilePath = filePath,
                    FileType = Path.GetExtension(file.FileName),
                    FileSize = file.Length.ToString(),
                    Description = request.Description,
                    Tags = request.Tags,
                    AccessLevel = request.AccessLevel,
                    Status = "pending",
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow,
                    User = user
                };

                _context.Documents.Add(document);
                await _context.SaveChangesAsync();

                var documentInfo = MapToDocumentInfo(document);
                successDocuments.Add(documentInfo);

                _logger.LogInformation("文档上传成功: {FileName}, ID: {Id}", file.FileName, document.Id);
            }
            catch (Exception ex)
            {
                var error = new UploadError
                {
                    FileName = file.FileName,
                    Error = ex.Message
                };
                failedDocuments.Add(error);
                _logger.LogError(ex, "文档上传失败: {FileName}", file.FileName);
            }
        }

        response.SuccessDocuments = successDocuments;
        response.FailedFiles = failedDocuments;
        response.TotalCount = request.Files.Count;
        response.SuccessCount = successDocuments.Count;
        response.FailedCount = failedDocuments.Count;

        return response;
    }

    public async Task<DocumentListResponse> GetDocumentsAsync(int page = 1, int pageSize = 20, string? keyword = null, string? accessLevel = null)
    {
        var query = _context.Documents.Include(d => d.User).AsQueryable();

        if (!string.IsNullOrEmpty(keyword))
        {
            query = query.Where(d => d.Title.Contains(keyword) || 
                                   d.FileName.Contains(keyword) || 
                                   (d.Description != null && d.Description.Contains(keyword)));
        }

        if (!string.IsNullOrEmpty(accessLevel))
        {
            query = query.Where(d => d.AccessLevel == accessLevel);
        }

        var totalCount = await query.CountAsync();
        var documents = await query
            .OrderByDescending(d => d.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var documentInfos = documents.Select(MapToDocumentInfo).ToList();

        return new DocumentListResponse
        {
            Documents = documentInfos,
            TotalCount = totalCount,
            Page = page,
            PageSize = pageSize,
            TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
        };
    }

    public async Task<DocumentInfo?> GetDocumentByIdAsync(Guid id)
    {
        var document = await _context.Documents
            .Include(d => d.User)
            .FirstOrDefaultAsync(d => d.Id == id);

        return document != null ? MapToDocumentInfo(document) : null;
    }

    public async Task<DocumentInfo?> UpdateDocumentAsync(Guid id, DocumentUpdateRequest updateRequest)
    {
        var document = await _context.Documents.FindAsync((object)id);
        if (document == null) return null;

        document.Title = updateRequest.Title;
        document.Description = updateRequest.Description;
        document.Tags = updateRequest.Tags;
        document.AccessLevel = updateRequest.AccessLevel;
        document.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();
        return MapToDocumentInfo(document);
    }

    public async Task<bool> DeleteDocumentAsync(Guid id)
    {
        var document = await _context.Documents.FindAsync((object)id);
        if (document == null) return false;

        try
        {
            if (!string.IsNullOrEmpty(document.FilePath))
            {
                await _fileStorage.DeleteAsync(document.FilePath);
            }

            _context.Documents.Remove(document);
            await _context.SaveChangesAsync();

            _logger.LogInformation("文档删除成功: {Id}", id);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "文档删除失败: {Id}", id);
            return false;
        }
    }

    public async Task<bool> DeleteDocumentsAsync(List<Guid> ids)
    {
        var documents = await _context.Documents.Where(d => ids.Contains(d.Id)).ToListAsync();
        if (!documents.Any()) return false;

        try
        {
            foreach (var document in documents)
            {
                if (!string.IsNullOrEmpty(document.FilePath))
                {
                    await _fileStorage.DeleteAsync(document.FilePath);
                }
            }

            _context.Documents.RemoveRange(documents);
            await _context.SaveChangesAsync();

            _logger.LogInformation("批量删除文档成功: {Count} 个", documents.Count);
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "批量删除文档失败");
            return false;
        }
    }

    public async Task<DocumentStatisticsResponse> GetDocumentStatisticsAsync()
    {
        var statistics = await _context.Documents
            .GroupBy(d => d.Status)
            .Select(g => new { Status = g.Key, Count = g.Count() })
            .ToListAsync();

        var totalFileSize = await _context.Documents
            .Where(d => !string.IsNullOrEmpty(d.FileSize))
            .SumAsync(d => long.Parse(d.FileSize ?? "0"));

        return new DocumentStatisticsResponse
        {
            TotalDocuments = await _context.Documents.CountAsync(),
            PendingDocuments = statistics.FirstOrDefault(s => s.Status == "pending")?.Count ?? 0,
            ProcessingDocuments = statistics.FirstOrDefault(s => s.Status == "processing")?.Count ?? 0,
            CompletedDocuments = statistics.FirstOrDefault(s => s.Status == "completed")?.Count ?? 0,
            FailedDocuments = statistics.FirstOrDefault(s => s.Status == "failed")?.Count ?? 0,
            TotalFileSize = totalFileSize
        };
    }

    private void ValidateFile(RAG.Domain.Services.FileInfo file)
    {
        if (file == null || file.Length == 0)
            throw new ArgumentException("文件不能为空");

        if (file.Length > 50 * 1024 * 1024)
            throw new ArgumentException("文件大小不能超过50MB");

        var allowedExtensions = new[] { ".pdf", ".doc", ".docx", ".txt", ".md", ".jpg", ".jpeg", ".png", ".ppt", ".pptx", ".xls", ".xlsx" };
        var extension = Path.GetExtension(file.FileName).ToLower();
        
        if (!allowedExtensions.Contains(extension))
            throw new ArgumentException("不支持的文件格式");
    }

    private DocumentInfo MapToDocumentInfo(Documents document)
    {
        return new DocumentInfo
        {
            Id = document.Id.ToString(),
            Title = document.Title,
            FileName = document.FileName,
            FilePath = document.FilePath,
            FileType = document.FileType,
            FileSize = document.FileSize,
            Description = document.Description,
            Tags = document.Tags,
            AccessLevel = document.AccessLevel,
            Status = document.Status,
            CreatedAt = document.CreatedAt,
            UpdatedAt = document.UpdatedAt,
            UserId = document.User?.Id.ToString(),
            UserName = document.User?.UserName
        };
    }
} 